iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
自我挑戰組

Vscode 實作:用 HTML/CSS/JS 打造醫藥健康小工具箱系列 第 26 篇

Day 26:【全站記憶】 LocalStorage 應用(上):用 JSON.stringify() 實現 Tool 3 與 Tool 4 紀錄永久化儲存

  • 分享至 

  • xImage
  •  

本篇文章目錄

  1. 前言:從「重新整理就歸零」到「狀態永久保存」
  2. LocalStorage 核心原理:網頁瀏覽器的持久化資料庫
  3. 實戰 JS 開發:物件陣列序列化與儲存寫入
  4. 程式碼重點與體驗細節解析
  5. 結語

一、 前言:從「重新整理就歸零」到「狀態永久保存」

在開發前端互動工具時,我們常遇到一個尷尬的現象:使用者開心地輸入了藥品名稱、開瓶日期與效期天數,甚至排好了全天的用藥時間表;但只要不小心按到 F5 重新整理,或是把頁面關掉重新開啟,所有的資料就瞬間「灰飛煙滅」。

一個成熟的 Web App,絕對不能讓使用者重複進行無意義的輸入。

在 Day 26 與 Day 27 這兩篇文章中,我們要為 [Tool 3 用藥時間表] 與 [Tool 4 開瓶倒數追蹤] 建立全站的資料記憶機制。今天這篇(上集),我們將聚焦於資料寫入與物件序列化(Serialization),透過 Web Storage API 的 localStorage.setItem() 與 JSON.stringify(),將陣列資料永久儲存在使用者的瀏覽器中!

二、 LocalStorage 核心原理:網頁瀏覽器的持久化資料庫

在 Web 開發中,若不需要透過 Server 或 API 存取資料庫,LocalStorage 是實作單機版資料持久化(Persistence)的最佳選擇。

LocalStorage 的三大關鍵特性:

  1. 跨 Session 永久保存:除非使用者主動清除瀏覽器快取,否則關閉分頁或重新開機,資料都會完整保留。
  2. 同源政策限制(Same-Origin Policy):資料綁定於特定 Domain、Protocol 與 Port,確保其他網站無法任意存取。
  3. 僅支援「字串(String)」格式:這是初學者最容易踩坑的地方!LocalStorage 只能儲存純文字字串。如果直接把 JavaScript 的物件(Object)或陣列(Array)丟進去,它會被強制轉型為毫無意義的 "[object Object]"。

為了在 LocalStorage 中儲存複雜的結構化資料(如包含 ID、名稱、日期的藥品清單陣列),我們必須使用 JSON.stringify() 將 JavaScript 物件轉換為 JSON 格式的文字字串。

三、 實戰 JS 開發:物件陣列序列化與儲存寫入

我們在 /tool4-timer.js 中處理輸入校正、封裝全新物件,並透過 saveAndRender() 執行序列化寫入:

/tool4-timer.js

// 2. 新增追蹤項目
btnAddTimer.addEventListener("click", () => {
  const nameInput = document.getElementById("item-name");
  const dateInput = document.getElementById("open-date");
  const expiryInput = document.getElementById("expiry-days");

  const name = nameInput.value.trim();
  const dateStr = dateInput.value;
  // 讀取效期天數,若未輸入或小於 1 則預設為 28 天
  const expiryDays = parseInt(expiryInput.value, 10) > 0 ? parseInt(expiryInput.value, 10) : 28;

  if (!name || !dateStr) {
    alert("請輸入藥品名稱與開瓶日期!");
    return;
  }

  const newItem = {
    id: Date.now(),
    name: name,
    openDate: dateStr,
    expiryDays: expiryDays // ✨ 儲存自訂的效期天數
  };

  timerItems.push(newItem);
  saveAndRender();

  // 清空輸入框並還原預設天數
  nameInput.value = "";
  dateInput.value = "";
  expiryInput.value = "28";
});

// 4. 儲存與渲染
function saveAndRender(){
  localStorage.setItem("med_timer_list", JSON.stringify(timerItems));
  renderTimers();
}

/tool3-schedule.js

// 5. 儲存與渲染
function saveAndRender(){
  localStorage.setItem("med_schedule_list", JSON.stringify(medList));
  renderSchedule();
}

四、 程式碼重點與體驗細節解析

1. Date.now() 建立不重複唯一識別碼(Unique ID)

在新增 newItem 物件時,我們使用 id: Date.now() 產生當下的毫秒時間戳記。這是一種極為高效且輕量的 ID 產生方式,能確保後續進行單項刪除或精準尋找時,不會因藥品名稱相同而誤刪其他項目。

2. 三元運算子與 parseInt() 進行防衛型數值校正

輸入框取得的數值皆為字串型態,透過 parseInt(expiryInput.value, 10) 轉為整數。
利用三元運算子 parseInt(...) > 0 ? parseInt(...) : 28 進行門檻校正,確保使用者輸入空值、0 或負數時,能自動降級回歸安全的預設值 28 天,維持資料欄位的合規性。

3. 單一功能原則(Single Responsibility)與 saveAndRender() 封裝

我們將 localStorage.setItem() 與 renderTimers() 統一收合進 saveAndRender() 函式中。
這樣設計的好處是:不管是「新增項目」、「修改項目」還是「刪除項目」,只要資料狀態發生改變,呼叫 saveAndRender() 就能同步確保資料庫更新與介面重繪,維持 UI 與 State 的絕對一致。

4. JSON.stringify() 物件序列化

在 localStorage.setItem("med_timer_list", JSON.stringify(timerItems)) 中,JSON.stringify() 扮演了關鍵的轉譯橋樑,將記憶體中的 JavaScript 陣列結構拍扁成符合 LocalStorage 規格的文字字串,實現長久的硬碟儲存。

五、 結語

今天我們完成了 [Tool 3] 與 [Tool 4] 的資料序列化與 LocalStorage 寫入機制,徹底解決了網頁重新整理後資料遺失的痛點,讓應用程式具備了基本且健全的狀態持久化能力。

然而,將資料成功存入瀏覽器只完成了一半!在明天的 [Day 27] 中,我們將進行 [【全站記憶】 LocalStorage 應用(下):用 JSON.parse() 讀取歷史紀錄與一鍵清空 LocalStorage 資料庫],實作頁面初始化時的反序列化載入與全防呆的一鍵清空機制。


上一篇
Day 25:【Tool 4 實作】倒數邏輯與動態進度條:依自訂效期計算剩餘百分比與 CSS 警示燈號切換
下一篇
Day 27:【全站記憶】 LocalStorage 應用(下):用 JSON.parse() 讀取歷史紀錄與一鍵清空 LocalStorage 資料庫
系列文
Vscode 實作:用 HTML/CSS/JS 打造醫藥健康小工具箱 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言